package com.sntk.organauthomanager.query;

import com.sntk.organauthomanager.application.dto.*;
import com.sntk.organauthomanager.application.mapper.OrganizationMapper;
import com.sntk.organauthomanager.infrastructure.commit.impl.MedicalOrganCommitConvert;
import com.sntk.organauthomanager.infrastructure.db.entity.OrganizationEntity;
import com.sntk.organauthomanager.infrastructure.db.entity.UserAffiliateEntity;
import com.sntk.organauthomanager.infrastructure.db.repository.OrganizationDBRepository;
import com.sntk.organauthomanager.infrastructure.db.repository.UserAffiliateDBRepository;
import com.sntk.organauthomanager.query.param.OrganCondition;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @ClassName: OrganizationQuery
 * @author: wgchao
 * @createTime: 2020/7/20 5:35 PM
 * @Description: TODO
 */
@Service
@Transactional(readOnly = true)
public class OrganizationQuery {
    @Autowired
    private OrganizationDBRepository organizationDBRepository;
    @Autowired
    private OrganizationMapper organizationMapper;
    @Autowired
    private UserAffiliateDBRepository userAffiliateDBRepository;
    @Autowired
    private MedicalOrganCommitConvert medicalOrganCommitConvert;

    public OrganizationDTO searchOrgan(String institutionNumber){
        OrganizationEntity organizationEntity = organizationDBRepository.findFirstByInstitutionNumberAndDelFalse(institutionNumber);
        if(organizationEntity == null){
            return null;
        }
        return organizationMapper.transformToDTO(organizationEntity);
    }

    public PageData<OrganizationVO> searchOrgansOfConditions(OrganCondition organCondition, OperatorInfo operatorInfo){
        Specification<OrganizationEntity> specification = new Specification<OrganizationEntity>() {
            @Override
            public Predicate toPredicate(Root<OrganizationEntity> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
                List<Predicate> predicateList = new ArrayList<>();
                //机构编号不为null 和 非3702
                if(!StringUtils.isEmpty(organCondition.getInstitutionNumber()) && !organCondition.getInstitutionNumber().equals("3702")){
                    if(organCondition.getChild()!=null && organCondition.getChild()){
                        Predicate predicate = criteriaBuilder.like(root.get("institutionNumber"), organCondition.getInstitutionNumber()+"%");
                        predicateList.add(predicate);
                    }else{
                        Predicate predicate = criteriaBuilder.equal(root.get("institutionNumber"), organCondition.getInstitutionNumber());
                        predicateList.add(predicate);
                    }
                }else{
                    //机构编码为null或者机构编号为3702
                    if(!operatorInfo.getOperator().equals("admin")){
                        if(organCondition.getChild()!=null && organCondition.getChild()){
                            Predicate predicate = criteriaBuilder.like(root.get("institutionNumber"), operatorInfo.getInstitutionNumber()+"%");
                            predicateList.add(predicate);
                        }else{
                            Predicate predicate = criteriaBuilder.equal(root.get("institutionNumber"), operatorInfo.getInstitutionNumber());
                            predicateList.add(predicate);
                        }
                    }
                }
                if(!StringUtils.isEmpty(organCondition.getInstitutionName())){
                    Predicate predicate = criteriaBuilder.like(root.get("institutionName"), organCondition.getInstitutionName()+"%");
                    predicateList.add(predicate);
                }
                if(organCondition.getDisabled() != null){
                    if(organCondition.getDisabled()){
                        Predicate predicate = criteriaBuilder.isTrue(root.get("disabled"));
                        predicateList.add(predicate);
                    }else{
                        Predicate predicate = criteriaBuilder.isFalse(root.get("disabled"));
                        predicateList.add(predicate);
                    }

                }
                Predicate predicate = criteriaBuilder.isFalse(root.get("del"));
                predicateList.add(predicate);

                Predicate[] predicates = new Predicate[predicateList.size()];
                return criteriaBuilder.and(predicateList.toArray(predicates));
            }
        };

        Pageable pageable = PageRequest.of(organCondition.getCurrPageNo()-1, organCondition.getLimit(), Sort.by(Sort.Order.asc("institutionNumber")));
        Page<OrganizationEntity> organPage = organizationDBRepository.findAll(specification, pageable);

        if(organPage.isEmpty()){
            return new PageData<>(0L, organCondition.getCurrPageNo(), null);
        }
        List<OrganizationVO> organizationVOS = organPage.stream().map(entity -> {
            return organizationMapper.transformToVO(entity);
        }).collect(Collectors.toList());
        return new PageData<>(organPage.getTotalElements(), organCondition.getCurrPageNo(), organizationVOS);
    }

    /**
     * 查询当前机构信息以及子级机构信息
     * @param institutionNumber
     * @return
     */
    public List<OrganizationVO> searchOrganChilds(String institutionNumber){
        List<OrganizationVO> organizationVOList = new ArrayList<>();

        if(institutionNumber.equals("3702")){
            List<OrganizationEntity> organizationEntityList =  organizationDBRepository.findAllByDelFalseOrderByInstitutionNumberAsc();
            if(organizationEntityList == null || organizationEntityList.isEmpty()){
                return null;
            }
            return organizationEntityList.stream().map(organizationEntity -> {
                return organizationMapper.transformToVO(organizationEntity);
            }).collect(Collectors.toList());

        }

        //当前机构
        OrganizationEntity organization = organizationDBRepository.findFirstByInstitutionNumberAndDelFalse(institutionNumber);
        if(organization == null){
            return null;
        }

        organizationVOList.add(organizationMapper.transformToVO(organization));
        List<OrganizationVO> childs = this.getClilds(organization);
        if(childs!=null){
            organizationVOList.addAll(childs);
        }

        return organizationVOList;
    }

    /**
     *
     * @param organizationEntity
     * @return
     */
    private List<OrganizationVO> getClilds(OrganizationEntity organizationEntity){

        List<OrganizationEntity> organizationEntityList = organizationDBRepository.findAllBySuperiorNumberAndDelFalseOrderByInstitutionNumberAsc(organizationEntity.getInstitutionNumber());

        if(organizationEntityList==null || organizationEntityList.isEmpty()){
            return null;
        }

        List<OrganizationVO> organizationVOList = organizationEntityList.stream().map(entry -> {
            OrganizationVO organizationVO = organizationMapper.transformToVO(entry);
                return organizationVO;
            }

        ).collect(Collectors.toList());

        return organizationVOList;
    }

    //查询用户关联机构信息

    public List<OrganizationDTO> findUserAffiliates(String uname){
        List<UserAffiliateEntity> userAffiliateEntities = userAffiliateDBRepository.findAllByUname(uname);
        if(userAffiliateEntities==null || userAffiliateEntities.isEmpty()){
            return null;
        }
        List<OrganizationDTO> organizationDTOS = userAffiliateEntities.stream().map(userAffiliateEntity -> {
            OrganizationEntity organizationEntity = organizationDBRepository.
                    findFirstByInstitutionNumberAndDelFalse(userAffiliateEntity.getInstitutionNumber());
            return organizationEntity==null ? null : organizationMapper.transformToDTO(organizationEntity);
        }).filter(od -> od != null).collect(Collectors.toList());

        return organizationDTOS;
    }


    public List<OrganizationDTO> searchUnallocatedGWOrgans(){
        List<String> codes = medicalOrganCommitConvert.searchAllocationOrgans();
        if(CollectionUtils.isEmpty(codes)){
            codes = new ArrayList<>();
            codes.add("");
        }
        List<OrganizationEntity> organs = organizationDBRepository.findAllByInstitutionNumberNotInAndDelFalseAndDisabledFalse(codes);
        if(CollectionUtils.isEmpty(organs)){
            return null;
        }
        return organs.stream().map(entity -> {
            OrganizationDTO dto = organizationMapper.transformToDTO(entity);
            return dto;
        }).collect(Collectors.toList());
    }

    public List<OrganizationDTO> queryOrganizationByName(String institutionName){
        List<OrganizationEntity> entities = organizationDBRepository.findAllByInstitutionNameLikeAndDisabledFalseAndDelFalse("%"+institutionName+"%");
        if(CollectionUtils.isEmpty(entities)){
            return null;
        }
        return entities.stream().map(entity -> {
            OrganizationDTO dto = organizationMapper.transformToDTO(entity);
            return dto;
        }).collect(Collectors.toList());
    }

    public List<OrganizationDTO> searchUnallocatedOrgansSetting(String institutionName){
        List<String> codes = medicalOrganCommitConvert.searchAllOrgansSetting();
        if(CollectionUtils.isEmpty(codes)){
            codes = new ArrayList<>();
            codes.add("");
        }
        institutionName = ObjectUtils.isEmpty(institutionName) ? "" : institutionName;
        List<OrganizationEntity> organs = organizationDBRepository.findAllByInstitutionNumberNotInAndInstitutionNameLikeAndDelFalseAndDisabledFalse(codes, "%"+ institutionName +"%");
        if(CollectionUtils.isEmpty(organs)){
            return null;
        }
        return organs.stream().map(entity -> {
            OrganizationDTO dto = organizationMapper.transformToDTO(entity);
            return dto;
        }).collect(Collectors.toList());
    }

}
